﻿using CNative.Utilities;
using Dapper;
using System;
using System.Collections.Generic;
#if !NET40
using System.ComponentModel.DataAnnotations.Schema;
#endif
using System.Data;
using System.Data.OleDb;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace CNative.Dapper.Utils
{
    public static class Funs
    {
        #region 缓存数据处理
        public static ICacheHelper CacheHelper = new MemoryCacheHelper();
        /// <summary>
        /// 从缓存中获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存项的唯一标识符</param>
        /// <param name="cachePopulate">>获取缓存值的操作(当缓存不存在相应的数据时，执行此方法获取数据)</param>
        /// <param name="expiresTime">缓存时长(分钟), enum ExpiresTime</param>
        /// <param name="isSliding">是否滑动过期（如果在过期时间内有操作，则以当前时间点延长过期时间）</param>
        /// <returns></returns>
        public static T CacheGet<T>(string key, Func<T> cachePopulate, ExpiresTime expiresTime = ExpiresTime.Minutes_30, Func<T, bool> checkPopulate = null)
        {
            return CacheHelper.Get<T>(key, cachePopulate, TimeSpan.FromMinutes(expiresTime.GetHashCode()), checkPopulate);
        }
        /// <summary>
        /// 设置缓存数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="expiresTime">缓存时长(分钟), enum ExpiresTime</param>
        /// <param name="isSliding">是否滑动过期（如果在过期时间内有操作，则以当前时间点延长过期时间）</param>
        /// <returns></returns>
        public static bool CacheSet(string key, object value, ExpiresTime expiresTime = ExpiresTime.Minutes_30)
        {
            return CacheHelper.Set(key, value, TimeSpan.FromMinutes(expiresTime.GetHashCode()));
        }
        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存项的唯一标识符</param>
        /// <returns></returns>
        public static bool CacheRemove(string key)
        {
            return MemoryCacheHelper.Instance.Remove(key);
        }
        public static void CacheRemoveAll()
        {
            MemoryCacheHelper.Instance.RemoveAll();
        }
        #endregion

        #region FormatFieldName
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="dicTableAlias">表别名字典</param>
        /// <param name="classType"></param>
        /// <param name="fieldName"></param>
        /// <param name="suffixLeft">前缀</param>
        /// <param name="suffixRigh">后缀</param>
        /// <returns></returns>
        public static string FormatFieldName(Type classType, string fieldName, string suffixLeft, string suffixRigh)
        {
            var tableAlias = "";
            if (classType != null)
            {
                tableAlias = SqlAliasHelper.GetTableAlias(classType);
            }
            return FormatFieldName(tableAlias, fieldName, suffixLeft, suffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="dicTableAlias">表别名字典</param>
        /// <param name="dbColumn">列实体</param>
        /// <param name="suffixLeft">前缀</param>
        /// <param name="suffixRigh">后缀</param>
        /// <returns></returns>
        public static string FormatFieldName(DbColumnInfo dbColumn, string suffixLeft, string suffixRigh)
        {
            if (dbColumn == null)
            {
                return "";
            }
            return FormatFieldName(dbColumn.PropertyInfo?.DeclaringType, dbColumn.Name, suffixLeft, suffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="dicTableAlias">表别名字典</param>
        /// <param name="classType"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public static string FormatFieldName(Type classType, string fieldName, SqlEntity sqlent)
        {
            var tableAlias = "";
            if (classType != null)
            {
                tableAlias = SqlAliasHelper.GetTableAlias(classType);
            }
            return FormatFieldName(tableAlias, fieldName, sqlent?.DbHelper?.SqlDbProvider.SuffixLeft, sqlent?.DbHelper?.SqlDbProvider.SuffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="dicTableAlias">表别名字典</param>
        /// <param name="dbColumn">列实体</param>
        /// <returns></returns>
        public static string FormatFieldName(DbColumnInfo dbColumn, SqlEntity sqlent)
        {
            if (dbColumn == null)
            {
                return "";
            }
            return FormatFieldName(dbColumn.PropertyInfo?.DeclaringType, dbColumn.Name, sqlent?.DbHelper?.SqlDbProvider.SuffixLeft, sqlent?.DbHelper?.SqlDbProvider.SuffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="dicTableAlias">表别名字典</param>
        /// <param name="dbColumn">列实体</param>
        /// <returns></returns>
        public static string FormatFieldName(DbColumnInfo dbColumn, BaseProvider dbProvider)
        {
            if (dbColumn == null)
            {
                return "";
            }
            return FormatFieldName(dbColumn.PropertyInfo?.DeclaringType, dbColumn.Name, dbProvider?.SuffixLeft, dbProvider?.SuffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="tableAlias">表别名字典</param>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public static string FormatFieldName(string tableAlias, string fieldName, BaseProvider dbProvider)
        {
            return FormatFieldName(tableAlias, fieldName, dbProvider?.SuffixLeft, dbProvider?.SuffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="tableAlias">表别名字典</param>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public static string FormatFieldName(string tableAlias, string fieldName, SqlEntity sqlent)
        {
            return FormatFieldName(tableAlias, fieldName, sqlent?.DbHelper?.SqlDbProvider.SuffixLeft, sqlent?.DbHelper?.SqlDbProvider.SuffixRigh);
        }
        /// <summary>
        /// 格式化字段
        /// </summary>
        /// <param name="tableAlias">表别名字典</param>
        /// <param name="fieldName">字段名</param>
        /// <param name="suffixLeft">前缀</param>
        /// <param name="suffixRigh">后缀</param>
        /// <returns></returns>
        public static string FormatFieldName(string tableAlias, string fieldName, string suffixLeft, string suffixRigh)
        {
            var fieldMeta = "{0}" + suffixLeft + "{1}" + suffixRigh + " ";
            tableAlias = tableAlias.NullToStr().Replace(".", "");
            tableAlias = tableAlias.Length > 0 ? tableAlias + "." : "";
            return string.Format(fieldMeta, tableAlias, fieldName.Trim());
        }
        public static bool IsInRange(this int thisValue, int begin, int end)
        {
            return thisValue >= begin && thisValue <= end;
        }

        public static bool IsInRange(this DateTime thisValue, DateTime begin, DateTime end)
        {
            return thisValue >= begin && thisValue <= end;
        }

        public static bool IsIn<T>(this T thisValue, params T[] values)
        {
            return values.Contains(thisValue);
        }
        public static bool IsContainsIn(this string thisValue, params string[] inValues)
        {
            return inValues.Any(it => thisValue.Contains(it));
        }
        public static bool HasValue(this object thisValue)
        {
            if (thisValue == null || thisValue == DBNull.Value) return false;
            return thisValue.ToString() != "";
        }

        public static bool HasValue(this IEnumerable<object> thisValue)
        {
            if (thisValue == null || thisValue.Count() == 0) return false;
            return true;
        }

        public static bool IsValuable(this IEnumerable<KeyValuePair<string, string>> thisValue)
        {
            if (thisValue == null || thisValue.Count() == 0) return false;
            return true;
        }
        public static bool IsZero(this object thisValue)
        {
            return (thisValue == null || thisValue.ToString() == "0");
        }

        public static bool IsInt(this object thisValue)
        {
            if (thisValue == null) return false;
            return Regex.IsMatch(thisValue.ToString(), @"^\d+$");
        }

        /// <returns></returns>
        public static bool IsNoInt(this object thisValue)
        {
            if (thisValue == null) return true;
            return !Regex.IsMatch(thisValue.ToString(), @"^\d+$");
        }

        public static bool IsMoney(this object thisValue)
        {
            if (thisValue == null) return false;
            double outValue = 0;
            return double.TryParse(thisValue.ToString(), out outValue);
        }
        public static bool IsGuid(this object thisValue)
        {
            if (thisValue == null) return false;
            Guid outValue = Guid.Empty;
            return Guid.TryParse(thisValue.ToString(), out outValue);
        }

        public static bool IsDate(this object thisValue)
        {
            if (thisValue == null) return false;
            DateTime outValue = DateTime.MinValue;
            return DateTime.TryParse(thisValue.ToString(), out outValue);
        }

        public static bool IsEamil(this object thisValue)
        {
            if (thisValue == null) return false;
            return Regex.IsMatch(thisValue.ToString(), @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$");
        }

        public static bool IsMobile(this object thisValue)
        {
            if (thisValue == null) return false;
            return Regex.IsMatch(thisValue.ToString(), @"^\d{11}$");
        }

        public static bool IsTelephone(this object thisValue)
        {
            if (thisValue == null) return false;
            return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{8}$");

        }

        public static bool IsIDcard(this object thisValue)
        {
            if (thisValue == null) return false;
            return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^(\d{15}$|^\d{18}$|^\d{17}(\d|X|x))$");
        }

        public static bool IsFax(this object thisValue)
        {
            if (thisValue == null) return false;
            return System.Text.RegularExpressions.Regex.IsMatch(thisValue.ToString(), @"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$");
        }

        public static bool IsMatch(this object thisValue, string pattern)
        {
            if (thisValue == null) return false;
            Regex reg = new Regex(pattern);
            return reg.IsMatch(thisValue.ToString());
        }
        public static bool IsAnonymousType(this Type type)
        {
            string typeName = type.Name;
            return typeName.Contains("<>") && typeName.Contains("__") && typeName.Contains("AnonymousType");
        }
        public static bool IsCollectionsList(this string thisValue)
        {
            return (thisValue + "").StartsWith("System.Collections.Generic.List") || (thisValue + "").StartsWith("System.Collections.Generic.IEnumerable");
        }
        public static bool IsStringArray(this string thisValue)
        {
            return (thisValue + "").IsMatch(@"System\.[a-z,A-Z,0-9]+?\[\]");
        }
        public static bool IsEnumerable(this string thisValue)
        {
            return (thisValue + "").StartsWith("System.Linq.Enumerable");
        }

        public static Type StringType = typeof(string);

        public static bool IsClass(this Type thisValue)
        {
            return thisValue != StringType && thisValue.IsEntity();
        }
        public static Type GetTypeInfo(this Type typeInfo)
        {
            return typeInfo;
        }

        public static Type[] GetGenericArguments(this Type type)
        {
            var reval = type.GetTypeInfo().GetGenericArguments();
            return reval;
        }
        public static bool IsGenericType(this Type type)
        {
            var reval = type.GetTypeInfo().IsGenericType;
            return reval;
        }
        public static PropertyInfo[] GetProperties(this Type type)
        {
            var reval = type.GetTypeInfo().GetProperties();
            return reval;
        }
        public static PropertyInfo GetProperty(this Type type, string name)
        {
            var reval = type.GetTypeInfo().GetProperty(name);
            return reval;
        }

        public static FieldInfo GetField(this Type type, string name)
        {
            var reval = type.GetTypeInfo().GetField(name);
            return reval;
        }

        public static bool IsEnum(this Type type)
        {
            var reval = type.GetTypeInfo().IsEnum;
            return reval;
        }

        public static bool IsValueType(this Type type)
        {
            return type.GetTypeInfo().IsValueType;
        }

        public static bool IsEntity(this Type type)
        {
            return type.GetTypeInfo().IsClass;
        }

        public static Type ReflectedType(this MethodInfo method)
        {
            return method.ReflectedType;
        }
        #endregion

        #region GetDbTableInfo/GetPropertys
        public static List<PropertyInfo> GetKeyPropertys<T>(IDbHelper dbHelper) where T : class, new()
        {
            var tb = GetDbTableInfo<T>(dbHelper);
            if (tb == null || tb.Columns == null || !tb.Columns.Exists(e => e.IsPrimaryKey))
            {
                var properties = Utilities.FastReflection.FastGetPropertyList<T>()
                    .Where(x => x.GetDbFieldMap()?.IsPrimaryKey == true)
                    .ToList();

                return properties;
            }
            else if (tb.Columns.Exists(e => e.IsPrimaryKey))
            {
                var properties = Utilities.FastReflection.FastGetPropertyList<T>()
                    .Where(x => tb.Columns.Exists(e => e.IsPrimaryKey && e.Name.Trim().ToUpper() == x.Name.Trim().ToUpper()))
                    .ToList();

                return properties;
            }
            else return new List<PropertyInfo>();
        }

        /// <summary>
        /// 通过连接字符串和表名获取数据库表的信息
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static DbTableInfo GetDbTableInfo<T>(this IDbHelper dbHelper) where T : class, new()
        {
            var tableType = typeof(T);
            return dbHelper.GetDbTableInfo(tableType);
        }
        /// <summary>
        /// 通过连接字符串和表名获取数据库表的信息
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static DbTableInfo GetDbTableInfo(this IDbHelper dbHelper, Type tableType)
        {
            if (tableType.IsNullOrEmpty()) return null;

            return CacheGet(tableType.FullName, () =>
            {
                var tb = GetDbTableName(tableType);
                var cols = GetDbDbColumnInfo(dbHelper, tb.TableName, tb.Schema);
                cols?.ForEach(c =>
                {
                    c.IsInTable = true;
                    var col = tb.GetColumn(c.Name);
                    if (col != null)
                    {
                        col.IsInTable = c.IsInTable;
                        col.ColumnId = c.ColumnId;
                        col.Name = c.Name;
                        col.Type = c.Type;
                        col.IsIdentity = c.IsIdentity;
                        col.IsNullable = c.IsNullable;
                        col.IsPrimaryKey = c.IsPrimaryKey;
                        col.MaxLength = c.MaxLength;
                        col.IsIgnore = c.IsIgnore;
                        col.DefaultValue = c.DefaultValue;
                        col.IndexGroupNameList = c.IndexGroupNameList;
                        col.UIndexGroupNameList = c.UIndexGroupNameList;
                    }
                    else tb.Columns.Add(c);
                });
                //tb.TableInfo = GetDbDbColumnInfo(dbHelper, tb.TableName, tb.Schema);

                return tb;
            });
        }
        public static string GetSchemaTableName<T>(this IDbHelper dbHelper) where T : class, new()
        {
            return GetSchemaTableName(dbHelper, typeof(T));
        }
        public static string GetSchemaTableName(this IDbHelper dbHelper, Type tableType)
        {
            if (dbHelper == null)
            {
                return "";
            }
            return dbHelper.SqlDbProvider.GetSchemaTableName(tableType);
        }
        //static DbTableInfo GetDbTableName<T>() where T : class, new()
        //{
        //    var tableType = typeof(T);
        //    return GetDbTableName(tableType);
        //}
        static DbTableInfo GetDbTableName(Type tableType)
        {
            DbTableInfo tb = new DbTableInfo() { TableName = tableType.Name };
            var EntityTableAttributes = tableType.GetCustomAttributes(typeof(TableMapAttribute), true);
            if (EntityTableAttributes != null && EntityTableAttributes.Length > 0)
            {
                var entityTableAttribute = EntityTableAttributes[0] as TableMapAttribute;
                tb = new DbTableInfo()
                {
                    TableName = entityTableAttribute.TableName.Trim().ToUpper(),
                    Schema = entityTableAttribute.Schema,
                    Description = entityTableAttribute.TableDescription,
                    IsDisabledDelete = entityTableAttribute.IsDisabledDelete,
                    IsDisabledUpdateAll = entityTableAttribute.IsDisabledUpdateAll
                };
                if (tb.TableName.IsNullOrEmpty())
                    throw new Exception(tableType.FullName + ",该实体没有表名标识！请使用[TableMap(TableName=\"表名\",Schema=\"库名\")]标识！");
                //if (tb.Schema.IsNullOrEmpty())
                //    throw new Exception(tableType.FullName + ",该实体没有库名标识！请使用[TableMap(TableName=\"表名\",Schema=\"库名\")]标识！");
            }
            else
            {
#if !NET40
                EntityTableAttributes = tableType.GetCustomAttributes(typeof(TableAttribute), true);
                if (EntityTableAttributes != null && EntityTableAttributes.Length > 0)
                {
                    var entityTableAttribute = EntityTableAttributes[0] as TableAttribute;
                    tb = new DbTableInfo()
                    {
                        TableName = entityTableAttribute.Name.Trim().ToUpper(),
                        Schema = entityTableAttribute.Schema
                    };
                    if (tb.TableName.IsNullOrEmpty())
                        throw new Exception(tableType.FullName + ",该实体没有表名标识！请使用[System.ComponentModel.DataAnnotations.Schema.Table(TableName=\"表名\",Schema=\"库名\")]标识！");
                }
#endif
                //throw new Exception(tableType.FullName + ",该实体没有表名标识！请使用[TableMap(TableName=\"表名\",Schema=\"库名\")]标识！");
            }

            // DbColumnInfo
            var columns = new List<DbColumnInfo>();
            var props = Utilities.FastReflection.FastGetPropertyList(tableType);
            foreach (var prop in props)
            {
                var col = new DbColumnInfo(prop);
                columns.Add(col);
                var attr = prop.GetCustomAttribute<DbFieldMapAttribute>();
                if (attr != null)
                {
                    col.Name = attr.CloumnName;
                    if (attr.Description.IsNotNullOrEmpty())
                        col.Description = attr.Description;
                    col.Type = attr.Type;
                    col.IsIdentity = attr.IsIdentity;
                    col.IsNullable = attr.IsNullable;
                    col.IsPrimaryKey = attr.IsPrimaryKey;
                    col.MaxLength = attr.MaxLength;
                    col.IsIgnore = attr.IsIgnore;
                    col.DefaultValue = attr.DefaultValue;
                    col.IndexGroupNameList = attr.IndexGroupNameList;
                    col.UIndexGroupNameList = attr.UIndexGroupNameList;
                }
                else
                {
                    col.Name = prop.Name;
                }

                var displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DisplayNameAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DisplayNameAttribute;
                    col.Description = displaya.DisplayName;
                }
#if !NET40
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DataAnnotations.DisplayAttribute;
                    col.Description = displaya.Name;
                }
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.KeyAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    col.IsPrimaryKey = true;
                }
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.MaxLengthAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DataAnnotations.MaxLengthAttribute;
                    col.MaxLength = displaya.Length;
                }
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.MinLengthAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DataAnnotations.MinLengthAttribute;
                    col.MaxLength = Math.Max(col.MaxLength, displaya.Length);
                }
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DataAnnotations.StringLengthAttribute;
                    col.MaxLength = Math.Max(col.MaxLength, Math.Max(displaya.MaximumLength, displaya.MinimumLength));
                }
                displayAs = tableType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DataTypeAttribute), true);
                if (displayAs != null && displayAs.Length > 0)
                {
                    var displaya = displayAs[0] as System.ComponentModel.DataAnnotations.DataTypeAttribute;
                    col.Type = displaya.GetDataTypeName();
                }
#endif

            }
            tb.Columns = columns;

            return tb;
        }
        /// <summary>
        /// 通过连接字符串和表名获取数据库表的信息
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static List<DbColumnInfo> GetDbDbColumnInfo(IDbHelper dbHelper, string tableName, string DbName)
        {
            if (tableName.IsNullOrEmpty())
                return new List<DbColumnInfo>();
            //---------------------------------------------------------------------
            var sqle = dbHelper.SqlDbProvider.GetDbTableInfoSQL(dbHelper, tableName, DbName);
            if (sqle == null) return new List<DbColumnInfo>();
            var list = new List<DbColumnInfo>();
            if (dbHelper.DBType == DatabaseType.Sqlite)
            {
                var dt = dbHelper.QueryDataTable(sqle);
                if (dt != null && dt.Rows.Count > 0)
                {
                    dt.Columns.Add(new DataColumn("table_name"));
                    dt.Columns.Add(new DataColumn("column_type"));
                    dt.Columns.Add(new DataColumn("MaxLength"));
                    foreach (DataColumn column in dt.Columns)
                    {
                        if (column.ColumnName.ToLower() == "cid") column.ColumnName = "ColumnId";
                        else if (column.ColumnName.ToLower() == "notnull") column.ColumnName = "IsNullable";
                        else if (column.ColumnName.ToLower() == "pk") column.ColumnName = "IsPrimaryKey";
                    }
                    foreach (DataRow dr in dt.Rows)
                    {
                        try
                        {
                            var typestr = dr["type"].NullToStr();
                            var typestrs = typestr.Split('(');
                            dr["table_name"] = "tableName";
                            dr["column_type"] = typestr;
                            dr["type"] = typestrs[0];
                            try
                            {
                                dr["MaxLength"] = typestrs.Length > 1 ? typestrs[1].Split(',', '(', ')')[0] : "0";
                            }
                            catch { }
                        }
                        catch { }
                    }
                    list = EntityHelper.DataTableToList<DbColumnInfo>(dt);
                }
            }
            else if (dbHelper.DBType == DatabaseType.MsAccess)
            {
                return GetTableFieldNameList(dbHelper, $"{tableName}");
            }
            else
            {
                //var dt = dbHelper.QueryDataTable(sqle);dt.DataTableToList<DbColumnInfo>();
                list = dbHelper.Query<DbColumnInfo>(sqle);
            }
            return list;
        }
        #region OleDb GetTableNameList/GetTableFieldNameList
        /// <summary>
        /// OleDb取所有表名
        /// </summary>
        /// <returns></returns>
        public static List<string> GetTableNameList(IDbHelper dbHelper, string stype = "TABLE")
        {
            List<string> list = new List<string>();
            var Conn = new OleDbConnection(dbHelper.ConnectString);
            try
            {
                if (Conn.State == ConnectionState.Closed)
                    Conn.Open();
                //DataTable shemaTable = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
                DataTable dt = Conn.GetSchema("Tables");
                foreach (DataRow row in dt.Rows)
                {
                    if (row[3].ToString() == stype)
                        list.Add(row[2].ToString());
                }
                return list;
            }
            catch (Exception e)
            {
                return list;
                //throw e;
            }
            finally { if (Conn.State == ConnectionState.Open) Conn.Close(); Conn.Dispose(); }
        }
        /// <summary>
        /// OleDb取指定表所有字段名称
        /// </summary>
        /// <returns></returns>
        public static List<DbColumnInfo> GetTableFieldNameList(IDbHelper dbHelper, string TableName)
        {
            var list = new List<DbColumnInfo>();
            var Conn = new OleDbConnection(dbHelper.ConnectString);
            try
            {
                if (Conn.State == ConnectionState.Closed)
                    Conn.Open();

                //var primary_Keys = new List<string>();
                //var schemaTable = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Primary_Keys, new Object[] { null, null, TableName });
                //if (schemaTable != null && schemaTable.Rows.Count > 0)
                //{
                //    for (int i = 0; i < schemaTable.Rows.Count; i++)
                //    {
                //        try
                //        {
                //            var colName = schemaTable.Rows[i].GetColumnValue("COLUMN_NAME").NullToStr();
                //            if (colName.IsNotNullOrEmpty()) primary_Keys.Add(colName);
                //        }
                //        catch { }
                //    }
                //}
                //var dt = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new Object[] { null, null, TableName, null });
                //if (dt != null && dt.Rows.Count > 0)
                //{
                //    for (int i = 0; i < dt.Rows.Count; i++)
                //    {
                //        var col = new DbColumnInfo();
                //        try
                //        {
                //            col.Name = dt.Rows[i].GetColumnValue("COLUMN_NAME").NullToStr();
                //            col.Description = dt.Rows[i].GetColumnValue("DESCRIPTION").NullToStr();
                //            col.ColumnId = dt.Rows[i].GetColumnValue("ORDINAL_POSITION").ToInt_();
                //            col.MaxLength = dt.Rows[i].GetColumnValue("CHARACTER_MAXIMUM_LENGTH").ToLong_();
                //            col.IsPrimaryKey = primary_Keys.Contains(col.Name);
                //            col.IsIdentity = col.IsPrimaryKey && dt.Rows[i].GetColumnValue("COLUMN_FLAGS").ToInt_() == 90;
                //            col.IsNullable = dt.Rows[i].GetColumnValue("IS_NULLABLE").ToBool_();
                //            var providerType = dt.Rows[i].GetColumnValue("DATA_TYPE").ToInt_();
                //            col.Type = ((OleDbType)providerType).ToString();
                //        }
                //        catch { }
                //        list.Add(col);
                //    }
                //}

                var adapter = new System.Data.OleDb.OleDbDataAdapter($"SELECT TOP 1 * FROM {dbHelper.SqlDbProvider.SuffixLeft}{TableName}{dbHelper.SqlDbProvider.SuffixRigh}", Conn);
                // Fill the DataTable, retrieving all the schema information.
                adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                adapter.MissingMappingAction = MissingMappingAction.Passthrough;
                DataTable table = new DataTable();
                adapter.Fill(table);
                // Create the DataTableReader, and close it when done.
                using (DataTableReader reader = new DataTableReader(table))
                {
                    var dt = reader.GetSchemaTable();
                    if (dt != null && dt.Rows.Count > 0)
                    {
                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            var col = new DbColumnInfo();
                            try
                            {
                                col.Name = dt.Rows[i].GetColumnValue("ColumnName").NullToStr();
                                col.ColumnId = dt.Rows[i].GetColumnValue("ColumnOrdinal").ToInt_();
                                col.MaxLength = dt.Rows[i].GetColumnValue("ColumnSize").ToLong_();
                                col.IsPrimaryKey = dt.Rows[i].GetColumnValue("IsKey").ToBool_();
                                col.IsIdentity = dt.Rows[i].GetColumnValue("IsAutoIncrement").ToBool_();
                                col.IsNullable = dt.Rows[i].GetColumnValue("AllowDBNull").ToBool_();
                                var providerType = dt.Rows[i].GetColumnValue("ProviderType").ToInt_();
                                col.Type = ((OleDbType)providerType).ToString();
                                col.IsInTable = true;
                            }
                            catch { }
                            list.Add(col);
                        }
                    }
                }

                var dt2 = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new Object[] { null, null, TableName, null });
                if (dt2 != null && dt2.Rows.Count > 0)
                {
                    for (int i = 0; i < dt2.Rows.Count; i++)
                    {
                        try
                        {
                            var colName = dt2.Rows[i].GetColumnValue("COLUMN_NAME").NullToStr();
                            var col = list.Find(f => f.Name == colName);
                            if (col != null)
                            {
                                var providerType = dt2.Rows[i].GetColumnValue("DATA_TYPE").ToInt_();
                                col.Type = ((OleDbType)providerType).ToString();
                            }
                        }
                        catch { }
                    }
                }
                adapter.Dispose();

                return list;
            }
            catch (Exception e)
            {
                return list;
                //throw e; 
            }
            finally
            {
                if (Conn.State == ConnectionState.Open)
                    Conn.Close();
                Conn.Dispose();
            }
        }
        #endregion
        #endregion

        #region GetColumnName
        /// <summary>
        /// 获取字段名称
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static string GetColumnName(this System.Reflection.MemberInfo member)
        {
            if (member == null) return "";
            var attr = member.GetDbFieldMap();
            if (attr != null && attr.CloumnName.IsNotNullOrEmpty())
            {
                return attr.CloumnName;
            }
            return member.Name;
        }
        /// <summary>
        /// 获取字段名称
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static string GetColumnName(this System.Reflection.PropertyInfo member)
        {
            return GetColumnName(member as System.Reflection.MemberInfo);
        }
        /// <summary>
        /// 获取字段名称
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static string GetColumnName(this System.Reflection.FieldInfo member)
        {
            return GetColumnName(member as System.Reflection.MemberInfo);
        }
        #endregion
        #region GetDbFieldMap
        /// <summary>
        /// 获取字段的映射特性
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static DbFieldMapAttribute GetDbFieldMap(this System.Reflection.MemberInfo member)
        {
            return member?.GetCustomAttribute<DbFieldMapAttribute>();
        }
        /// <summary>
        /// 获取字段的映射特性
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static DbFieldMapAttribute GetDbFieldMap(this System.Reflection.PropertyInfo member)
        {
            return GetDbFieldMap(member as System.Reflection.MemberInfo);
        }
        /// <summary>
        /// 获取字段的映射特性
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static DbFieldMapAttribute GetDbFieldMap(this System.Reflection.FieldInfo member)
        {
            return GetDbFieldMap(member as System.Reflection.MemberInfo);
        }
        #endregion

        #region LookupDbType
        public static System.Data.DbType LookupDbType(this Type type)
        {
            if (typeMap.TryGetValue(type, out DbType dbType))
            {
                return dbType;
            }
            //-----------------------------------------------------------
            if (type == Constants.ByteArrayType)
            {
                return System.Data.DbType.Binary;
            }
            else if (type == Constants.GuidType)
            {
                return System.Data.DbType.Guid;
            }
            else if (type == Constants.IntType)
            {
                return System.Data.DbType.Int32;
            }
            else if (type == Constants.ShortType)
            {
                return System.Data.DbType.Int16;
            }
            else if (type == Constants.LongType)
            {
                return System.Data.DbType.Int64;
            }
            else if (type == Constants.DateType)
            {
                return System.Data.DbType.DateTime;
            }
            else if (type == Constants.DobType)
            {
                return System.Data.DbType.Double;
            }
            else if (type == Constants.DecType)
            {
                return System.Data.DbType.Decimal;
            }
            else if (type == Constants.ByteType)
            {
                return System.Data.DbType.Byte;
            }
            else if (type == Constants.FloatType)
            {
                return System.Data.DbType.Single;
            }
            else if (type == Constants.BoolType)
            {
                return System.Data.DbType.Boolean;
            }
            else if (type == Constants.StringType)
            {
                return System.Data.DbType.String;
            }
            else if (type == Constants.DateTimeOffsetType)
            {
                return System.Data.DbType.DateTimeOffset;
            }
            //else if (type == Constants.TimeSpanType)
            //{
            //    if (this.Value != null)
            //        this.Value = this.Value.ToString();
            //}
            else if (type != null && type.IsEnum)
            {
                return System.Data.DbType.Int64;
            }
            return System.Data.DbType.String;

        }
        static Dictionary<Type, DbType> typeMap = new Dictionary<Type, DbType>(37)
        {
            [typeof(byte)] = DbType.Byte,
            [typeof(sbyte)] = DbType.SByte,
            [typeof(short)] = DbType.Int16,
            [typeof(ushort)] = DbType.UInt16,
            [typeof(int)] = DbType.Int32,
            [typeof(uint)] = DbType.UInt32,
            [typeof(long)] = DbType.Int64,
            [typeof(ulong)] = DbType.UInt64,
            [typeof(float)] = DbType.Single,
            [typeof(double)] = DbType.Double,
            [typeof(decimal)] = DbType.Decimal,
            [typeof(bool)] = DbType.Boolean,
            [typeof(string)] = DbType.String,
            [typeof(char)] = DbType.StringFixedLength,
            [typeof(Guid)] = DbType.Guid,
            [typeof(DateTime)] = DbType.DateTime,
            [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
            [typeof(TimeSpan)] = DbType.Time,
            [typeof(byte[])] = DbType.Binary,
            [typeof(byte?)] = DbType.Byte,
            [typeof(sbyte?)] = DbType.SByte,
            [typeof(short?)] = DbType.Int16,
            [typeof(ushort?)] = DbType.UInt16,
            [typeof(int?)] = DbType.Int32,
            [typeof(uint?)] = DbType.UInt32,
            [typeof(long?)] = DbType.Int64,
            [typeof(ulong?)] = DbType.UInt64,
            [typeof(float?)] = DbType.Single,
            [typeof(double?)] = DbType.Double,
            [typeof(decimal?)] = DbType.Decimal,
            [typeof(bool?)] = DbType.Boolean,
            [typeof(char?)] = DbType.StringFixedLength,
            [typeof(Guid?)] = DbType.Guid,
            [typeof(DateTime?)] = DbType.DateTime,
            [typeof(DateTimeOffset?)] = DbType.DateTimeOffset,
            [typeof(TimeSpan?)] = DbType.Time,
            [typeof(object)] = DbType.Object
        };
        /*
        AnsiString:VarChar
        Binary:VarBinary
        Byte:TinyInt
        Boolean:Bit
        Currency:Money
        Date:DateTime
        DateTime:DateTime
        Decimal:Decimal
        Double:Float
        Guid:UniqueIdentifier
        Int16:SmallInt
        Int32:Int
        Int64:BigInt
        Object:Variant
        Single:Real
        String:NVarChar
        Time:DateTime
        AnsiStringFixedLength:Char
        StringFixedLength:NChar
        Xml:Xml
        DateTime2:DateTime2
        DateTimeOffset:DateTimeOffset
         */

        public static System.Data.SqlDbType LookupSqlDbType(Type type)
        {
            if (TypeToSqlDbType.TryGetValue(type, out SqlDbType dbType))
            {
                return dbType;
            }
            return SqlDbType.VarChar;
        }
        /// <summary>
        /// Data Type to Db Type mapping dictionary for SQL Server
        /// https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
        /// </summary>

        public static readonly Dictionary<Type, SqlDbType> TypeToSqlDbType = new Dictionary<Type, SqlDbType>
            {
              // Mapping C# types to Ado.net SqlDbType enumeration
                {typeof (byte), SqlDbType.TinyInt},
                {typeof (sbyte), SqlDbType.TinyInt},
                {typeof (short), SqlDbType.SmallInt},
                {typeof (ushort), SqlDbType.SmallInt},
                {typeof (int), SqlDbType.Int},
                {typeof (uint), SqlDbType.Int},
                {typeof (long), SqlDbType.BigInt},
                {typeof (ulong), SqlDbType.BigInt},
                {typeof (float), SqlDbType.Float},
                {typeof (double), SqlDbType.Float},
                {typeof (decimal), SqlDbType.Decimal},
                {typeof (bool), SqlDbType.Bit},
                {typeof (string), SqlDbType.VarChar},
                {typeof (char), SqlDbType.Char},
                {typeof (Guid), SqlDbType.UniqueIdentifier},
                {typeof (DateTime), SqlDbType.DateTime},
                {typeof (DateTimeOffset), SqlDbType.DateTimeOffset},
                {typeof (byte[]), SqlDbType.VarBinary},
                {typeof (byte?), SqlDbType.TinyInt},
                {typeof (sbyte?), SqlDbType.TinyInt},
                {typeof (short?), SqlDbType.SmallInt},
                {typeof (ushort?), SqlDbType.SmallInt},
                {typeof (int?), SqlDbType.Int},
                {typeof (uint?), SqlDbType.Int},
                {typeof (long?), SqlDbType.BigInt},
                {typeof (ulong?), SqlDbType.BigInt},
                {typeof (float?), SqlDbType.Float},
                {typeof (double?), SqlDbType.Float},
                {typeof (decimal?), SqlDbType.Decimal},
                {typeof (bool?), SqlDbType.Bit},
                {typeof (char?), SqlDbType.Char},
                {typeof (Guid?), SqlDbType.UniqueIdentifier},
                {typeof (DateTime?), SqlDbType.DateTime},
                {typeof (DateTimeOffset?), SqlDbType.DateTimeOffset},
                //{typeof (System.Data.Linq.Binary), SqlDbType.Binary},
                {typeof (IEnumerable<>), SqlDbType.Structured},
                {typeof (List<>), SqlDbType.Structured},
                {typeof (DataTable), SqlDbType.Structured},

            };

        #endregion
        #region ListToSqlStr
        /// <summary>
        /// 
        /// </summary>
        /// <param name="listobj"></param>
        /// <returns></returns>
        public static string ListToSqlStr(IEnumerable<object> listobj)
        {
            if (listobj.IsNullOrEmpty() || listobj.Count() == 0)
            {
                return "";//In 中为空时，直接返回false
            }
            else
            {
                var str = "";
                listobj.ForEach(val =>
                {
                    if (val.IsNullOrEmpty()) return;
                    var pstr = "";
                    typeSqlStr.TryGetValue(val.GetType(), out pstr);
                    str += pstr + val + pstr + ",";
                });
                str = str.Trim(',');
                return str;
            }
        }
        static Dictionary<Type, string> typeSqlStr = new Dictionary<Type, string>(37)
        {
            [typeof(byte)] = "",
            [typeof(sbyte)] = "",
            [typeof(short)] = "",
            [typeof(ushort)] = "",
            [typeof(int)] = "",
            [typeof(uint)] = "",
            [typeof(long)] = "",
            [typeof(ulong)] = "",
            [typeof(float)] = "",
            [typeof(double)] = "",
            [typeof(decimal)] = "",
            [typeof(bool)] = "",
            [typeof(string)] = "'",
            [typeof(char)] = "'",
            [typeof(Guid)] = "'",
            [typeof(DateTime)] = "'",
            [typeof(DateTimeOffset)] = "'",
            [typeof(TimeSpan)] = "'",
            [typeof(byte[])] = "'",
            [typeof(byte?)] = "",
            [typeof(sbyte?)] = "",
            [typeof(short?)] = "",
            [typeof(ushort?)] = "",
            [typeof(int?)] = "",
            [typeof(uint?)] = "",
            [typeof(long?)] = "",
            [typeof(ulong?)] = "",
            [typeof(float?)] = "",
            [typeof(double?)] = "",
            [typeof(decimal?)] = "",
            [typeof(bool?)] = "",
            [typeof(char?)] = "'",
            [typeof(Guid?)] = "'",
            [typeof(DateTime?)] = "'",
            [typeof(DateTimeOffset?)] = "'",
            [typeof(TimeSpan?)] = "'",
            [typeof(object)] = "'",
        };
        #endregion

        #region CreateTable
        /// <summary>
        ///  Convert IEnumerable<T> to DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <returns></returns>
        public static DataTable CreateTable<T>(this IEnumerable<T> collection)
        {
            // Fetch the type of List contained in the ParamValue
            var tableType = typeof(T);

            // Create DataTable which will contain data from List<T>
            var dataTable = new DataTable();

            // Fetch the Type fields count
            int columnCount = tableType.GetProperties().Count();

            var columnNameMappingDictionary = new Dictionary<string, string>();

            // Create DataTable Columns using table type field name and their types
            // Traversing through Column Collection
            for (int counter = 0; counter < columnCount; counter++)
            {
                var propertyInfo = tableType.GetProperties()[counter];

                //var parameterAttribute = propertyInfo.GetParameterAttribute();
                string columnName = /*(parameterAttribute != null) ? parameterAttribute.Name : */propertyInfo.Name;

                columnNameMappingDictionary.Add(propertyInfo.Name,
                   /* (parameterAttribute != null) ? parameterAttribute.Name : */propertyInfo.Name);

                dataTable.Columns.Add(columnName, tableType.GetProperties()[counter].PropertyType);
            }

            // Return parameter with null value
            if (collection == null)
                return dataTable;

            // Traverse through number of entries / rows in the List
            foreach (var item in collection)
            {
                // Create a new DataRow
                DataRow dataRow = dataTable.NewRow();

                // Traverse through type fields or column names
                for (int counter = 0; counter < columnCount; counter++)
                {
                    // Fetch Column Name
                    string columnName = columnNameMappingDictionary[tableType.GetProperties()[counter].Name];

                    //Fetch Value for each column for each element in the List<T>
                    dataRow[columnName] = item
                        .GetType().GetProperties()[counter]
                        .GetValue(item, null);
                }
                // Add Row to Table
                dataTable.Rows.Add(dataRow);
            }

            return (dataTable);
        }

        /// <summary>
        /// Convert IEnumerable<T> to DataTable
        /// </summary>
        /// <param name="paramValue"></param>
        /// <returns></returns>
        public static DataTable CreateTable(object paramValue)
        {
            // Fetch the type of List contained in the ParamValue
            Type tableType = paramValue.GetType().GetGenericArguments()[0];

            // Create DataTable which will contain data from List<T>
            var genericDataTable = new DataTable();

            // Fetch the Type fields count
            int fieldCount = tableType.GetProperties().Count();

            // Create DataTable Columns using table type field name and their types
            // Traversing through Column Collection
            for (int counter = 0; counter < fieldCount; counter++)
            {
                genericDataTable.Columns.Add(tableType.GetProperties()[counter].Name,
                    tableType.GetProperties()[counter].PropertyType);
            }

            // Traverse through number of entries / rows in the List
            foreach (var item in (System.Collections.IEnumerable)paramValue)
            {
                // Create a new DataRow
                DataRow dataRow = genericDataTable.NewRow();

                // Traverse through type fields or column names
                for (int counter = 0; counter < fieldCount; counter++)
                {
                    // Fetch Column Name
                    string columnName = tableType.GetProperties()[counter].Name;

                    //Fetch Value for each column for each element in the List<T>
                    dataRow[columnName] = item
                        .GetType().GetProperties()[counter]
                        .GetValue(item, null);
                }
                // Add Row to Table
                genericDataTable.Rows.Add(dataRow);
            }
            return genericDataTable;
        }
        #endregion

        #region PageEach
        public static void PageEach<T>(this IEnumerable<T> pageItems, int pageSize, Action<List<T>> action)
        {
            if (pageItems != null && pageItems.Any())
            {
                int totalRecord = pageItems.Count();
                int pageCount = (totalRecord + pageSize - 1) / pageSize;
                for (int i = 1; i <= pageCount; i++)
                {
                    var list = pageItems.Skip((i - 1) * pageSize).Take(pageSize).ToList();
                    action(list);
                }
            }
        }
        #endregion

        #region GetEntityNameByTableName
        /// <summary>
        /// 去除表名或列名中的特殊符号
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static string GetEntityNameByTableName(string tableName)
        {
            string rtn = "";
            //去除tableName中的特殊符号: _
            //1.去掉tableName中的T_、V_和MV_
            if (tableName.StartsWith("T_") || tableName.StartsWith("V_") || tableName.StartsWith("VP_"))
            {
                tableName = tableName.Substring(2, tableName.Length - 2);
            }
            if (tableName.StartsWith("MV_"))
            {
                tableName = tableName.Substring(3, tableName.Length - 3);
            }
            return tableName.Replace("_", "");
            //2.将第一个字母大写, _ 后面的单词的第一个字母大写
            string[] tableNameArray = tableName.Split('_');
            if (tableNameArray.Length > 0)
            {
                foreach (string subName in tableNameArray)
                {
                    string tempName = subName.ToLower();
                    if (tempName.Length >= 1)
                    {
                        tempName = tempName.Substring(0, 1).ToUpper() + tempName.Substring(1, subName.Length - 1);
                    }
                    rtn += tempName;
                }
            }
            return rtn;
        }
        #endregion

        #region GetStackTrace
        public static StackTraceInfo GetStackTrace()
        {
            var st = new System.Diagnostics.StackTrace(true);
            StackTraceInfo info = new StackTraceInfo();
            info.MyStackTraceList = new List<StackTraceInfoItem>();
            for (int i = 0; i < st.FrameCount; i++)
            {
                var frame = st.GetFrame(i);
                if (frame.GetMethod().Name.First() != '<')
                {
                    info.MyStackTraceList.Add(new StackTraceInfoItem()
                    {
                        FileName = frame.GetFileName(),
                        MethodName = frame.GetMethod().Name,
                        Line = frame.GetFileLineNumber()
                    });
                }
            }
            return info;
        }
        #endregion

        #region Convert
        internal static Type GetRootBaseType(Type entityType)
        {
            var baseType = entityType.BaseType;
            while (baseType != null && baseType.BaseType != Constants.ObjType)
            {
                baseType = baseType.BaseType;
            }
            return baseType;
        }


        internal static Type GetUnderType(PropertyInfo propertyInfo, ref bool isNullable)
        {
            Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
            isNullable = unType != null;
            unType = unType ?? propertyInfo.PropertyType;
            return unType;
        }

        internal static Type GetUnderType(PropertyInfo propertyInfo)
        {
            Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
            unType = unType ?? propertyInfo.PropertyType;
            return unType;
        }

        internal static bool IsNullable(PropertyInfo propertyInfo)
        {
            Type unType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
            return unType != null;
        }

        internal static bool IsNullable(Type type)
        {
            Type unType = Nullable.GetUnderlyingType(type);
            return unType != null;
        }
        internal static T IsNullReturnNew<T>(T returnObj) where T : new()
        {
            if (returnObj.IsNullOrEmpty())
            {
                returnObj = new T();
            }
            return returnObj;
        }

        public static int ObjToInt(this object thisValue)
        {
            int reval = 0;
            if (thisValue == null) return 0;
            if (thisValue is Enum)
            {
                return (int)thisValue;
            }
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }

        public static int ObjToInt(this object thisValue, int errorValue)
        {
            int reval = 0;
            if (thisValue is Enum)
            {
                return (int)thisValue;
            }
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static double ObjToMoney(this object thisValue)
        {
            double reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }

        public static double ObjToMoney(this object thisValue, double errorValue)
        {
            double reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static string ObjToString(this object thisValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return "";
        }

        public static string ObjToString(this object thisValue, string errorValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return errorValue;
        }

        public static Decimal ObjToDecimal(this object thisValue)
        {
            Decimal reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }

        public static Decimal ObjToDecimal(this object thisValue, decimal errorValue)
        {
            Decimal reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static DateTime ObjToDate(this object thisValue)
        {
            DateTime reval = DateTime.MinValue;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                reval = Convert.ToDateTime(thisValue);
            }
            return reval;
        }

        public static DateTime ObjToDate(this object thisValue, DateTime errorValue)
        {
            DateTime reval = DateTime.MinValue;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static bool ObjToBool(this object thisValue)
        {
            bool reval = false;
            if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }
        #endregion

        #region 获取类中的属性
        /// <summary>
        /// 获取类中的属性
        /// </summary>
        /// <returns>所有属性名称</returns>
        public static List<string> GetPropertyNames<T>(this T t)
        {
            List<string> ListStr = new List<string>();
            if (t == null)
            {
                return ListStr;
            }
            System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            if (properties.Length <= 0)
            {
                return ListStr;
            }
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                string name = item.Name; //名称
                object value = item.GetValue(t, null);  //值
                if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
                {
                    ListStr.Add(name);
                }
                else
                {
                    GetPropertyNames(value);
                }
            }
            return ListStr;
        }
        /// <summary>
        ///  获取类中的字段
        /// </summary>
        /// <returns>所有字段名称</returns>
        public static List<string> GetFieldNames<T>(this T t)
        {
            List<string> ListStr = new List<string>();
            if (t == null)
            {
                return ListStr;
            }
            System.Reflection.FieldInfo[] fields = t.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            if (fields.Length <= 0)
            {
                return ListStr;
            }
            foreach (System.Reflection.FieldInfo item in fields)
            {
                string name = item.Name; //名称
                object value = item.GetValue(t);  //值

                if (item.FieldType.IsValueType || item.FieldType.Name.StartsWith("String"))
                {
                    ListStr.Add(name);
                }
                else
                {
                    GetFieldNames(value);
                }
            }
            return ListStr;
        }
        #endregion
        #region 获得字符串中开始和结束字符串中间得值
        /// <summary>
        /// 获得字符串中开始和结束字符串中间得值
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="s">开始</param>
        /// <param name="e">结束</param>
        /// <returns></returns> 
        public static List<string> GetRegexValue(this string str, string s, string e)
        {
            s = s.Replace("(", "\\(").Replace(")", "\\)").Replace("[", "\\[").Replace("]", "\\]");
            e = e.Replace("(", "\\(").Replace(")", "\\)").Replace("[", "\\[").Replace("]", "\\]");

            var rg = new System.Text.RegularExpressions.Regex("(?<=(" + s + "))[.\\s\\S]*?(?=(" + e + "))"
                , System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.Singleline);

            var lst = new List<string>();
            var mc = rg.Matches(str);
            foreach (System.Text.RegularExpressions.Match item in mc)
            {
                if (item.Value.IsNotNullOrEmpty())
                {
                    lst.Add(item.Value);
                }
            }
            return lst;
        }
        #endregion

        #region Replace
        /// <summary>
        /// 只替换第一个匹配项，写一个方法来实现这个功能。
        /// </summary>
        /// <param name="source"></param>
        /// <param name="match"></param>
        /// <param name="replacement"></param>
        /// <returns></returns>
        public static string Replace(string source, string match, string replacement)
        {
            char[] sArr = source.ToCharArray();
            char[] mArr = match.ToCharArray();
            char[] rArr = replacement.ToCharArray();
            int idx = IndexOf(sArr, mArr);
            if (idx == -1)
            {
                return source;
            }
            else
            {
                return new string(sArr.Take(idx).Concat(rArr).Concat(sArr.Skip(idx + mArr.Length)).ToArray());
            }
        }
        /// <summary>
        /// 查找字符数组在另一个字符数组中匹配的位置
        /// </summary>
        /// <param name="source">源字符数组</param>
        /// <param name="match">匹配字符数组</param>
        /// <returns>匹配的位置，未找到匹配则返回-1</returns>
        private static int IndexOf(char[] source, char[] match)
        {
            int idx = -1;
            for (int i = 0; i <= source.Length - match.Length; i++)
            {
                if (source[i] == match[0])
                {
                    bool isMatch = true;
                    for (int j = 0; j < match.Length; j++)
                    {
                        if (source[i + j] != match[j])
                        {
                            isMatch = false;
                            break;
                        }
                    }
                    if (isMatch)
                    {
                        idx = i;
                        break;
                    }
                }
            }
            return idx;
        }
        #endregion
    }
}
